package com.niiwoo.civet.user.service.local;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.niiwoo.civet.user.constants.UserRedisKey;
import com.niiwoo.civet.user.dao.entity.DataStatus;
import com.niiwoo.civet.user.dto.request.DataStatusRequestDTO;
import com.niiwoo.civet.user.dto.response.DataStatusResponseDTO;
import com.niiwoo.civet.user.dto.response.ThirdAuthResponseDTO;
import com.niiwoo.civet.user.enums.UserDataStatusEnum;
import com.niiwoo.civet.user.enums.UserDataTypeEnum;
import com.niiwoo.civet.user.service.UserAuthDubboService;
import com.niiwoo.civet.user.service.UserStatusDubboService;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.tiancheng.component.TianchengAuthService;
import com.niiwoo.tripod.tiancheng.request.auth.ThirdAuthCallbackRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;

import java.io.IOException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.Date;

/**
 * @author DELL
 * @create 2018-04-17 11:44
 * @desc 授权公用模板service
 **/
@Slf4j
public abstract class UserAuthCommonTemplateService {

    private static final String TIANCHENG_SUCCESS_STATUS = "1";

    private static final String MARK = "1";

    @Autowired
    private UserStatusService userStatusService;

    @Autowired
    PrivacyMasks privacyMasks;

    @Value(value = "${web-http-url}")
    private String webHttpUrl;

    @Value(value = "${h5-root-url}")
    private String h5RootUrl;

    @Autowired
    UserAuthDubboService userAuthDubboService;

    /**
     * 信用卡回调授权成功通知地址
     */
    //private final String CREDIT_CARD_NOTIFY_URL = "/userAuth/creditCardAuthNotifyCallback";



    @Autowired
    private UserAuthCommonService userAuthCommonService;

    @Autowired
    private UserStatusDubboService userStatusDubboService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 信用卡获取到数据回调地址
     */
    //private final String CREDIT_CARD_CALLBACK_URL = "/tc/authCreditCardData/callback";

    /**
     * 上次授权失败原因显示结果页面
     */
    //private final String h5ErrorMsgUrl = "{0}/html5/project/creditresult/index.html#/authorizeFail?t={1}&msg={2}";
    public abstract String getH5ErrorMsgUrl();
    /**
     * 天秤授权同步get回调h5页面地址
     */
    //private final String h5CallbackResultUrl = "/html5/project/creditresult/index.html#/";
    public abstract String getH5CallbackResultUrl();

    /**
     * 数据回调页面
     * @return
     */
    public abstract String getDataCallbackUrl();

    /**
     * 业务名称
     * @return
     */
    public abstract String getAuthBizName();

    /**
     * 获取授权的中文名称，用于页面提示文字显示，如：信用卡，学历。。
     * @return
     */
    public abstract String getAuthChineseName();

    /**
     * 认证类别
     * @return
     */
    public abstract UserDataTypeEnum getDataType();





    /**
     * 获取天秤第三方授权h5页面的url
     *
     * @param userId   用户id
     * @param createIp 用户客户端请求ip
     * @return com.niiwoo.civet.user.dto.response.ThirdAuthResponseDTO
     * @author zzl
     * @date 2017/11/22 16:20
     */
    public ThirdAuthResponseDTO getThirdAuthUrl(String userId, String createIp, String source) {

        //查询授权状态
        DataStatus existsUserStatus = userStatusService.getByUserIdAndType(userId, getDataType());
        Byte dataStatus = null;
        if (existsUserStatus != null) {
            dataStatus = existsUserStatus.getDataStatus();
            //已授权或已验证，直接返回
            if (UserDataStatusEnum.CreditCardStatus.GETSUCCESS.getStatus().equals(existsUserStatus.getDataStatus())
                    ||UserDataStatusEnum.CreditCardStatus.ALREADY_CREDIT.getStatus().equals(existsUserStatus.getDataStatus())) {
                ThirdAuthResponseDTO dto = new ThirdAuthResponseDTO();
                dto.setStatus(UserDataStatusEnum.CreditCardStatus.GETSUCCESS.getStatus().toString());
                dto.setUserDataStatus(dataStatus);
                return dto;
            }
        } else {
            dataStatus = UserDataStatusEnum.CreditCardStatus.NOCREDIT.getStatus();
        }

        //处理及获取上次信用卡授权错误信息
        boolean cleanErrorMsgTag = false;
        String userAuthErrorMsgKey = UserRedisKey.AUTH_ERROR_MSG + getAuthBizName() + userId;
        try {
            if (redisTemplate.hasKey(userAuthErrorMsgKey)) {
                Object cacheObj = redisTemplate.opsForValue().get(userAuthErrorMsgKey);
                if (cacheObj != null) {
                    String errorMsg = (String) cacheObj;
                    if (StringUtils.isNotBlank(errorMsg)) {
                        if(!MARK.equals(source)) {//如果是H5错误页面的请求
                            String encodeErrorMsg = URLEncoder.encode(errorMsg, "UTF8");
//                            redisTemplate.setRet(0);
                            ThirdAuthResponseDTO dto = new ThirdAuthResponseDTO();
                            String h5msgurl = MessageFormat.format(getH5ErrorMsgUrl(), h5RootUrl, String.valueOf(System.currentTimeMillis()), encodeErrorMsg);
                            dto.setUrl(h5msgurl);
                            return dto;
                        }else{
                            cleanErrorMsgTag = true;
                        }
                    }
                }
            }
        }catch (Exception e){
            log.error("从redis获取" + getAuthBizName() + "授权错误信息失败", e);
        }


        //请求天秤获取授权链接
        ThirdAuthResponseDTO dto = userAuthCommonService.getThirdAuthUrl(userId, createIp, getTianchengAuthService(), null,
                webHttpUrl + getDataCallbackUrl(),
//                webHttpUrl + getH5CallbackResultUrl(),
                h5RootUrl + getH5CallbackResultUrl(),
                false, null);
        dto.setUserDataStatus(dataStatus);

        //不用删除上次信用卡授权错误信息，直接返回
        if(!cleanErrorMsgTag){
            return dto;
        }

        //删除上次信用卡授权错误信息
        try{
            redisTemplate.delete(userAuthErrorMsgKey);
        }catch (Exception e){
            log.error("删除" + getAuthBizName() + "授权错误信息失败" , e);
        }

        return dto;
    }

    public boolean authCallback(String resultJson){
        return commonCallback(resultJson,TIANCHENG_SUCCESS_STATUS,true, UserDataStatusEnum.CreditCardStatus.ALREADY_CREDIT,UserDataStatusEnum.CreditCardStatus.NOCREDIT,getAuthBizName() + "AuthCallback");
    }

    public boolean dataCallBack(String resultJson){
        return commonCallback(resultJson,TIANCHENG_SUCCESS_STATUS,false, UserDataStatusEnum.CreditCardStatus.GETSUCCESS,UserDataStatusEnum.CreditCardStatus.GETFAIL,getAuthBizName() + "DataCallback");
    }

    private boolean commonCallback(String result, String successFlag, boolean isAuthCallback, UserDataStatusEnum.CreditCardStatus successStatus, UserDataStatusEnum.CreditCardStatus failStatus, String logTag){
        //参数判断处理及解密
        ThirdAuthCallbackRequest callbackRequest = null;
        String jsonResult = StringUtils.replace(result, " ", "+");
        log.info(logTag + "回调后参数：" + jsonResult);
        JSONObject busiData = null;
        try {
            busiData = userAuthDubboService.resolveEncryptCallbackData(jsonResult);
            log.info(logTag + "回调解密后参数：" + busiData.toJSONString());
            callbackRequest = JSONObject.parseObject(busiData.toJSONString(), ThirdAuthCallbackRequest.class);
        } catch (IOException e) {
            log.info(logTag + "回调数据解析错误");
            throw new BizException("解析错误");
        }
        if (callbackRequest == null) {
            log.info(logTag + "回调参数为空");
            throw new BizException("参数为空");
        }

        //对京东授权数据回调的特殊赋值处理
        String jdLoginname = null;
        if(!isAuthCallback) {
            if (UserDataTypeEnum.JD_AUTHORIZE.equals(getDataType())) {
                if(!StringUtils.isBlank(callbackRequest.getUserInfo())) {//天秤有调整
                    JSONObject userInfo = busiData.getJSONObject("userInfo");
                    if (userInfo != null) {
                        if (StringUtils.isBlank(callbackRequest.getUserId())) {
                            callbackRequest.setUserId(userInfo.getString("userId"));
                        }
                        jdLoginname = userInfo.getString("loginName");
                    }
                }
                JSONObject data = busiData.getJSONObject("data");
                if(data != null){
                    if("10000".equals(data.getString("code"))){
                        callbackRequest.setStatus("1");
                    }
                    JSONObject jdResult=data.getJSONObject("result");
                    if(jdResult!=null){
                        jdLoginname = jdResult.getString("loginname");
                    }
                }
            }
        }

        log.info(logTag + "回调userId={},请求参数={}", callbackRequest.getUserId(), callbackRequest);
        if (StringUtils.isBlank(callbackRequest.getUserId())
                || StringUtils.isBlank(callbackRequest.getStatus())
                || StringUtils.isBlank(callbackRequest.getAuthorizeType())) {
            log.info(logTag + "回调参数为空", callbackRequest);
            throw new BizException("参数为空");
        }
        log.debug(logTag + "成功回调：" + JSON.toJSONString(callbackRequest));

        //判断回调状态
        String userId = callbackRequest.getUserId();

        //判断已数据回调成功，就直接返回成功
        DataStatusResponseDTO existsData = userStatusDubboService.getByUserIdAndType(userId, getDataType());
        if (existsData != null) {
            if (UserDataStatusEnum.CreditCardStatus.GETSUCCESS.getStatus().equals(existsData.getDataStatus())) {
                log.info(callbackRequest.getUserId() + getAuthBizName() + "已经数据回调成功，直接返回");
                return true;
            }
        }
        //授权回调如果已经处理，就直接返回
        if(isAuthCallback) {
            if (existsData != null) {
                if (UserDataStatusEnum.CreditCardStatus.ALREADY_CREDIT.getStatus().equals(existsData.getDataStatus())) {
                    log.info(callbackRequest.getUserId() + getAuthBizName() + "已经授权回调成功，直接返回");
                    return true;
                }
            }
        }

        DataStatusRequestDTO dataStatusRequestDTO = new DataStatusRequestDTO();
        dataStatusRequestDTO.setDataType(getDataType().getValue());
        dataStatusRequestDTO.setUserId(userId);

        Byte status = null;
        Date now = new Date();
        if (TIANCHENG_SUCCESS_STATUS.equals(callbackRequest.getStatus())) {
            status = successStatus.getStatus();
            if(isAuthCallback){//授权成功回调
                dataStatusRequestDTO.setAuthTime(now);
            }else{//数据成功回调
                if(UserDataTypeEnum.CREDIT_CARD_AUTHORIZE.equals(getDataType())) {
                    saveDataCallback(userId, callbackRequest.getUserInfo());
                }else if(UserDataTypeEnum.JD_AUTHORIZE.equals(getDataType())){
                    saveDataCallback(userId, jdLoginname);
                }else if(UserDataTypeEnum.EDUCATION_AUTHORIZE.equals(getDataType())){
                    saveDataCallback(userId, null);
                }
            }

        } else {
            status = failStatus.getStatus();

            //如果失败是数据回调产生的，解析及保存错误信息到Redis
            if(!isAuthCallback){
                String tianchengReturnStatus = callbackRequest.getStatus();
                String errorMsg = null;
                if("3".equals(tianchengReturnStatus)){
                    errorMsg = MessageFormat.format("抱歉，您所查询的{0}信息与您身份信息不符，请输入您本人的{0}信息进行查询！", getAuthChineseName());
                }else if("2".equals(tianchengReturnStatus)){
                    String msg = callbackRequest.getMsg();
                    if(StringUtils.isNotBlank(msg)){
                        errorMsg = msg;
                    }else {
                        errorMsg = "数据获取超时/失败，请重新授权";
                    }
                }
                if(StringUtils.isBlank(errorMsg)){
                    errorMsg = "服务器繁忙，请重新授权";
                }
                String userAuthErrorMsgKey = UserRedisKey.AUTH_ERROR_MSG + getAuthBizName() + userId;
                redisTemplate.opsForValue().set(userAuthErrorMsgKey , errorMsg);
            }
        }

        //修改修改用户数据状态及返回结果
        dataStatusRequestDTO.setUpdateTime(now);
        dataStatusRequestDTO.setDataStatus(status);
        int saveResult = userStatusDubboService.saveDataStatusByUserIdAndType(dataStatusRequestDTO);
        if (saveResult <= 0) {
            log.error(logTag + "用户状态数据更新失败:" + JSON.toJSONString(dataStatusRequestDTO));
            throw new BizException("用户状态数据更新失败");
        }

        return true;
    }

    public abstract void saveDataCallback(String userId, String jsonString);

    public abstract TianchengAuthService getTianchengAuthService();

}
